#include <jni.h>
#include <string>
#include <x264.h>
#include <pthread.h>
#include "librtmp/rtmp.h"
#include "VideoChannel.h"
#include "AudioChannel.h"
#include "safe_queue.h"

VideoChannel *videoChannel;
AudioChannel *audioChannel;
//为了防止用户重复点击开始直播
int isStart = 0;
pthread_t pid;
uint32_t start_time;
int readyPushing = 0;
//队列，类似Java中ArrayBlockingQueue
SafeQueue<RTMPPacket *> packets;

//释放packet
void releasePackets(RTMPPacket *&packet) {
    if (packet) {
        RTMPPacket_Free(packet);
        delete packet;
        packet = 0;
    }
}

void callback(RTMPPacket *packet) {
    if (packet) {
        packet->m_nTimeStamp = RTMP_GetTime() - start_time;
        //加入队列
        packets.enQueue(packet);
    }
}

//链接服务器
void *start(void *args) {
    char *url = static_cast<char *>(args);
    RTMP *rtmp = 0;
    rtmp = RTMP_Alloc();
    if (!rtmp) {
        return NULL;
    }
    //初始化
    RTMP_Init(rtmp);
    //设置地址
    int ret = RTMP_SetupURL(rtmp, url);
    if (!ret) {
        return NULL;
    }
    //设置链接时间
    rtmp->Link.timeout = 5;
    //开启可写入RTMP
    RTMP_EnableWrite(rtmp);
    //连接服务器
    ret = RTMP_Connect(rtmp, 0);
    if (!ret) {
        return NULL;
    }

    ret = RTMP_ConnectStream(rtmp, 0);
    if (!ret) {
        return NULL;
    }

    start_time = RTMP_GetTime();
    //表示可以推流了
    readyPushing = 1;
    packets.setWork(1);
    RTMPPacket *packet = 0;
    callback(audioChannel->getAudioTag());
    while (readyPushing) {
        //队列去数据 packets
        packets.deQueue(packet);
        if (!readyPushing) {
            break;
        }
        if (!packet) {
            continue;
        }
        //设置数据包，流类型
        packet->m_nInfoField2 = rtmp->m_stream_id;
        //发送数据包
        ret = RTMP_SendPacket(rtmp, packet, 1);
        //发送完之后要释放packet
        releasePackets(packet);
    }

    isStart = 0;
    readyPushing = 0;
    packets.setWork(0);
    packets.clear();
    if (rtmp) {
        RTMP_Close(rtmp);
        RTMP_Free(rtmp);
    }
    delete(url);
}

extern "C" JNIEXPORT jstring JNICALL
Java_com_zsd_android_rtmpdemo_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {

    x264_picture_t* x264_picture = new x264_picture_t;
    RTMP_Alloc();

    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

extern "C"
JNIEXPORT void JNICALL
Java_com_zsd_android_rtmpdemo_bean_CameraHelper_nativeInit(JNIEnv *env, jobject instance) {

    videoChannel = new VideoChannel;
    videoChannel->setVideoCallback(callback);
    audioChannel = new AudioChannel;
    audioChannel->setAudioCallback(callback);
}

extern "C"
JNIEXPORT void JNICALL
Java_com_zsd_android_rtmpdemo_bean_CameraHelper_nativeSetVideoEncInfo(JNIEnv *env, jobject instance,
                                                                 jint width, jint height, jint fps,
                                                                 jint bitrate) {
    if (!videoChannel) {
        return;
    }
    videoChannel->setVideoEncInfo(width, height, fps, bitrate);
}

extern "C"
JNIEXPORT void JNICALL
Java_com_zsd_android_rtmpdemo_bean_CameraHelper_nativeStart(JNIEnv *env, jobject instance,
                                                            jstring path_) {
    const char *path = env->GetStringUTFChars(path_, 0);

    //初始化线程
    if (isStart) {
        return;
    }
    isStart = 1;

    char  *url = new char[strlen(path) + 1];
    strcpy(url, path);

    //开启线程
    pthread_create(&pid, 0, start, url);
    env->ReleaseStringUTFChars(path_, path);
}

extern "C"
JNIEXPORT void JNICALL
Java_com_zsd_android_rtmpdemo_bean_CameraHelper_nativePushVideo(JNIEnv *env, jobject instance,
                                                                jbyteArray data_) {
    if (!videoChannel || !readyPushing) {
        return;
    }
    jbyte *data = env->GetByteArrayElements(data_, NULL);
    videoChannel->encodeData(data);

    env->ReleaseByteArrayElements(data_, data, 0);
}

extern "C"
JNIEXPORT void JNICALL
Java_com_zsd_android_rtmpdemo_bean_CameraHelper_nativePushAudio(JNIEnv *env, jobject instance,
                                                                jbyteArray data_) {
    jbyte *data = env->GetByteArrayElements(data_, NULL);

    if (!audioChannel || !readyPushing) {
        return;
    }
    audioChannel->encodeData(data);
    env->ReleaseByteArrayElements(data_, data, 0);
}

extern "C"
JNIEXPORT void JNICALL
Java_com_zsd_android_rtmpdemo_bean_CameraHelper_nativeSetAudioEncInfo(JNIEnv *env, jobject instance,
                                                                      jint sampleRateInHz, jint channels) {

    if (audioChannel) {
        audioChannel->setAudioEncInfo(sampleRateInHz, channels);
    }

}